/*
 * Copyright 2014, General Dynamics C4 Systems
 *
 * SPDX-License-Identifier: GPL-2.0-only
 *//*Z 中断处理机制：用户空间的驱动调用seL4_IRQHandler_SetNotification()设置Notification对象，
中断发生时内核Signal()该对象，正在Wait()的驱动接收到通知并开始处理，然后调用seL4_IRQHandler_Ack()通知内核处理结束 */

#pragma once

#include <config.h>
#include <types.h>
#include <util.h>

#include <arch/object/structures.h>
#include <arch/model/statedata.h>
#include <arch/kernel/apic.h>
#include <machine/interrupt.h>
#include <plat/machine/acpi.h>
#include <plat/machine/ioapic.h>
#include <plat/machine/pic.h>
#include <plat/machine/intel-vtd.h>
/*Z 处理保留类IRQ，打印有关信息 */
static inline void handleReservedIRQ(irq_t irq)
{
#ifdef CONFIG_IOMMU
    if (irq == irq_iommu) {
        vtd_handle_fault();
        return;
    }
#endif

#ifdef CONFIG_IRQ_REPORTING
    printf("Received unhandled reserved IRQ: %d\n", (int)irq);
#endif
}
/*Z 接收因屏蔽而pending的中断，更新x86KSPendingInterrupt全局变量 */
static inline void receivePendingIRQ(void)
{
    assert(ARCH_NODE_STATE(x86KSPendingInterrupt) == int_invalid);
    asm volatile("sti\n"    /*Z 启用中断 */
                 "nop\n"    /*Z 如果有中断pending，此指令后pending中断会进来 */
                 "cli\n"
                 : "=m"(ARCH_NODE_STATE(x86KSPendingInterrupt)));/*Z 因为是嵌套中断，对放进来的中断处理只是更新此全局变量 */
}
/*Z 查找全局变量返回待处理的中断向量号 */
static inline interrupt_t servicePendingIRQ(void)
{
    assert(ARCH_NODE_STATE(x86KScurInterrupt) == int_invalid);
    assert(ARCH_NODE_STATE(x86KSPendingInterrupt) != int_invalid);
    interrupt_t ret = ARCH_NODE_STATE(x86KSPendingInterrupt);
    ARCH_NODE_STATE(x86KSPendingInterrupt) = int_invalid;
    return ret;
}
/*Z 返回当前正处理的中断IRQ号，如果没有就轮询pending中断 */
/* Get the IRQ number currently working on. */
static inline irq_t getActiveIRQ(void)
{
    if (ARCH_NODE_STATE(x86KScurInterrupt) == int_invalid) {
        /* If we tried to get the active IRQ when we don't have one then
         * we are polling for an interrupt for some reason, in which case
         * we should try to get a pending interrupt if there isn't already
         * one.
         * This logic is here and not in the main call sites in handleSyscall
         * because this is only relevant on some interrupt controllers (notably
         * the x86 APIC) and is cleaner to have here */
        if (ARCH_NODE_STATE(x86KSPendingInterrupt) == int_invalid) {
            receivePendingIRQ();/*Z 接收因屏蔽而pending的中断 */
            /* Check if there was no pending IRQ */
            if (ARCH_NODE_STATE(x86KSPendingInterrupt) == int_invalid) {
                return irqInvalid;
            }
        }
        /* Prepare to handle pending IRQ *//*Z 查找全局变量返回待处理的中断向量号 */
        ARCH_NODE_STATE(x86KScurInterrupt) = servicePendingIRQ();
    }
    return ARCH_NODE_STATE(x86KScurInterrupt) - IRQ_INT_OFFSET;
}
/*Z 是否有中断pending */
/* Checks for pending IRQ */
static inline bool_t isIRQPending(void)
{   /*Z 是否有中断pending */
    if (apic_is_interrupt_pending()) {
        return true;
    }

    if (config_set(CONFIG_IRQ_PIC) && pic_is_irq_pending()) {
        return true;
    }

    return false;
}
/*Z 发送中断服务完成信号 */
static inline void ackInterrupt(irq_t irq)
{
    if (config_set(CONFIG_IRQ_PIC) && irq <= irq_isa_max) {
        pic_ack_active_irq();/*Z 向PIC发出当前中断服务完成的信号 */
    } else {
        apic_ack_active_interrupt();/*Z 向xAPIC发送中断服务完成信号 */
    }
}
/*Z 空函数 */
static inline void handleSpuriousIRQ(void)
{
    /* do nothing */
}
/*Z 给全局变量x86KSIRQState[irq]赋值state */
static void inline updateIRQState(irq_t irq, x86_irq_state_t state)
{
    assert(irq <= maxIRQ);
    x86KSIRQState[irq] = state;
}
/*Z 设置第irq个硬件中断的禁用掩码，1-禁用，0-启用 */
static inline void maskInterrupt(bool_t disable, irq_t irq)
{
    if (irq >= irq_isa_min && irq <= irq_isa_max) { /*Z 8259A */
        if (config_set(CONFIG_IRQ_PIC)) {
            pic_mask_irq(disable, irq);             /*Z 设置0～15号PIC中断是否禁用 */
        } else {
            /* We shouldn't receive interrupts on the PIC range
             * if not using the PIC, but soldier on anyway */
        }
    } else if (irq >= irq_user_min && irq <= irq_user_max) {            /*Z I/O APIC等 */
        x86_irq_state_t state = x86KSIRQState[irq];
        switch (x86_irq_state_get_irqType(state)) {
        case x86_irq_state_irq_ioapic: {
            uint32_t ioapic = x86_irq_state_irq_ioapic_get_id(state);   /*Z 获取I/O APIC编号 */
            uint32_t pin = x86_irq_state_irq_ioapic_get_pin(state);     /*Z 获取中断线号 */
            ioapic_mask(disable, ioapic, pin);                          /*Z 设置中断掩码 */
            state =  x86_irq_state_irq_ioapic_set_masked(state, disable);
            updateIRQState(irq, state);                                 /*Z 保存在全局状态中 */
        }
        break;
        case x86_irq_state_irq_msi:
            /* currently MSI interrupts can not be disabled */
            break;
        case x86_irq_state_irq_free:
            /* A spurious interrupt, and the resulting mask here,
             * could be from a user ripping out a vector before
             * the interrupt reached the kernel. Silently ignore */
            break;
        }
    } else {
        /* masking some other kind of interrupt source, this probably
         * shouldn't happen, but soldier on */
    }
}

